home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Communication
/
NewsBase
/
Source
/
INewsGroupTreeControl.m
< prev
next >
Wrap
Text File
|
1993-01-12
|
24KB
|
787 lines
/*$Copyright:
* Copyright (C) 1992.5.22. Recruit Co.,Ltd.
* Institute for Supercomputing Research
* All rights reserved.
* NewsBase by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue
*
* You may freely copy, distribute and reuse the code in this program under
* following conditions.
* - to include this notice in the source code, if it is to be distributed
* with source code.
* - to add the file named "COPYING" within the code, which shall include
* GNU GENERAL PUBLIC LICENSE(*).
* - to display an acknowledgement in binary code as follows: "This product
* includes software developed by Recruit Co.,Ltd., ISR."
* - to display a notice which shall state that the users may freely copy,
* distribute and reuse the code in this program under GNU GENERAL PUBLIC
* LICENSE(*)
* - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*)
*
* (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
$*/
/*
* INewsGroupTreeControl is a subclass of the INNTP class.
* It initializes and maintains the newsgroup tree.
* It also handles the posting of articles.
* It handles all communication with the NNTP server.
*/
#import <appkit/appkit.h>
#import <streams/streams.h>
#import <objc/zone.h>
#import <mach/mach.h>
#import <defaults/defaults.h>
#import <strings.h>
#import <libc.h>
#import <ctype.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <errno.h>
#import <dpsclient/dpsNeXT.h>
#import "INewsGroupTreeControl.h"
#import "data_types.h"
#import "response_codes.h"
#import "InfoD.h"
#import "INewsRc.h"
#import "INewsgroupInfoD.h"
#import "ITreeNodeD.h"
#import "IReceiveSpeaker.h"
#import "errdebug.h"
#import "Localization.h"
#define LoStr(key) doLocalString(NULL,key,NULL)
#define OWNER "NewsBase"
#define NNTPSERVER "NNTPServer"
//#define MAX_NO_OF_TOKENS 256
//#define OK_GROUPS 215 /* Newsgroups follow */
id currentNewsGroup;
id currentArticle;
@implementation INewsGroupTreeControl
- initServer:(char *)nntpHost allNews:(BOOL)allNewsFlag
{
/* connect to nntp server */
if ([self openServer:nntpHost]==nil) {
return nil;
}
/* set rootName to IOmodule, this will be used for the root name */
/* on newsgroup browser */
[self setRootName:nntpHost];
// set flag for reading all news group or subscribed only
iAllNewsFlag = allNewsFlag;
/* make newsgroup tree zone */
newsgroupTreeZone = NXCreateZone (vm_page_size, vm_page_size, YES);
/* read .newsrc file and make string table */
if ([self readNewsRcFile] ==NULL) {
return NULL;
}
iNewsGroupTreeRoot = [[ITreeNodeD allocFromZone:
(NXZone *)newsgroupTreeZone] initWithKey:"root"];
// make news group tree
[self listAndMakeNewsgroupTree];
// start auto reconnecting timed entry event
[self setTimedEntryForReconnect];
return self;
}
- listAndMakeNewsgroupTree
{
int statusCode;
id groupInfoD;
char groupName[256], canPost[2];
// char groupnameTmp[256];
char *groupnameTmp;
int last, first;
char ch, tempbuf[LINE_BUFFER_SIZE];
char *key[MAX_NO_OF_TOKENS];
ITreeNodeD *node;
void makeTreeKey(const char *, const char **, const char *);
statusCode = [self issueCommand:"list"];
if (statusCode != OK_GROUPS) {
NXRunAlertPanel([self name],LoStr("list command failed"),
LoStr("OK"),NULL,NULL);
[NXApp terminate:self];
}
canPost[1] = '\0';
while ((ch = fgetc(inntpFile)) !='.') {
ungetc (ch, inntpFile);
fscanf (inntpFile, "%[^\r]\r\n", tempbuf);
sscanf (tempbuf, "%255s %d %d %c", groupName, &last, &first, &canPost);
/* check canPost is '='(alias) */
if (canPost[0] == '=') {
/* if the newsgroup is aliased, skip this group */
continue;
}
/* check group name */
/* Subscribe and NotExist -> make node for news group tree */
/* UnSubscribe -> not to make into tree */
switch ((NewsStat)[iNewsRc isSubscribe:groupName]) {
case UnSubscribe:
if (iAllNewsFlag == NO) {
/* unsubscribed newsgroup is marked as not-active */
/* only subscribed newsgroup, so skip unsubscribed one */
continue;
}
/* iAllNewsFlag == YES */
break;
case NotExist:
fprintf (stderr,
"WARNING: new group \"%s\" is added\n", groupName);
case Subscribe:
break;
}
// if iNewsGroupTreeRoot already had the node for key,
// the node has already been created. if not, make it.
//strncpy(groupnameTmp, groupName, sizeof(groupnameTmp)-1);
groupnameTmp = NXCopyStringBuffer(groupName);
makeTreeKey(groupnameTmp, key, ".");
if ((node=[iNewsGroupTreeRoot nodeForKey:key]) == nil) {
node = [iNewsGroupTreeRoot addNodeForKey:key];
}
free(groupnameTmp);
if((groupInfoD = [node dataForKey:GROUPINFO]) == nil) {
/* node does not have groupInfoD, so initialize it */
/* when launching NewsBase first, this routine will be called, */
/* but not entering when reconnecting. */
groupInfoD = [[INewsgroupInfoD allocFromZone:
(NXZone *)newsgroupTreeZone] initWithKey:GROUPINFO];
[groupInfoD addInfo:groupName key:GROUPNAME];
[node insertKeyedObject:groupInfoD];
/* set other info. from header field */
// set FIRST, CANPOST, ART_NUM_SET when launched
// skip these when reconnecting
[groupInfoD addInfoInt:first key:FIRST];
[groupInfoD addInfo:canPost key:CANPOST];
/* set ART_NUM_SET */
/* "addInfoInt: key:FIRST" will clean up ART_NUM_SET, */
/* but response of list command includes poor infomation about */
/* FIRST, so locate ART_NUM_SET after "addInfoInt: key:FIRST" */
/* not to waste cpu */
[iNewsRc setGroupInfo:groupInfoD];
}
// LAST will be reset when reconnecting
[groupInfoD addInfoInt:last key:LAST];
}
fgetc (inntpFile); /* get \r */
fgetc (inntpFile); /* get \n */
/* move file pointer to the end of stream */
fseek (inntpFile, (long)0, SEEK_END);
return self;
}
- newsGroupTreeRoot
{
return iNewsGroupTreeRoot;
}
- (const char *)currentNewsgroupName
{
// return [[iCurrentNewsgroup link] key];
return [[iCurrentNewsgroup dataForKey:GROUPINFO] infoForKey:GROUPNAME];
}
- currentArticleItem
{
return iCurrentArticleItem;
}
- initNewsGroup:newsGroup readFlag:(ReadFlag)rflag
{
char combuf[LINE_CHR_MAX];
id groupInfoD;
int statusCode;
int dum, estNum, first, last, tmpint;
int i;
id articleDB;
int artWillGetNum, artNumAmount;
/* headersZone is for ItemHeaderBrowser */
/* when newsgroup is switched, headers are no longer needed */
if (headersZone != NULL) {
NXDestroyZone(headersZone);
}
headersZone = NXCreateZone (vm_page_size, vm_page_size, YES);
DBG(1, fprintf(stderr, "headersZone = %x\n", (unsigned int)headersZone););
articleDB = [[IOrderedListD allocFromZone:headersZone]
initWithKey:"articleDB"];
groupInfoD = [newsGroup dataForKey:GROUPINFO];
strncpy (combuf, "group ", 7);
strncat (combuf, (char *)[groupInfoD infoForKey:GROUPNAME], (LINE_CHR_MAX-7));
statusCode = [self issueCommand:combuf];
if (statusCode != OK_GROUP) {
if (statusCode == ERR_NOGROUP) {
NXRunAlertPanel(LoStr("WARNING"),
LoStr("InntpTalk: no such newsgroup"),LoStr("OK"),NULL,NULL);
} else {
NXRunAlertPanel(LoStr("ERROR"),
LoStr("InntpTalk: group command failed"),LoStr("OK"),NULL,NULL);
fseek (inntpFile, (long)0, SEEK_END);
return nil;
}
}
sscanf (iresponse, "%d %d %d %d", &dum, &estNum, &first, &last);
/* dum is status code */
tmpint = (int)[groupInfoD infoForKey:LAST];
if (tmpint != last) {
[groupInfoD addInfoInt:last key:LAST];
}
tmpint = (int)[groupInfoD infoForKey:FIRST];
if (tmpint != first) {
[groupInfoD addInfoInt:first key:FIRST];
}
[groupInfoD addInfoInt:estNum key:ESTIMATENUM];
fseek (inntpFile, (long)0, SEEK_END);
/* # of articles on server */
/* read check */
switch ( rflag ) {
case ALL:
for (i=first; i<=last; i++) {
[self commandHead:i articleDB:articleDB];
}
break;
case UNMARKEDONLY:
default:
/* default # of getting article from server is in NUM_ARTTOGET */
if ((artNumAmount=[groupInfoD countArticleUnMarked])
> (int)atoi(NXGetDefaultValue(OWNER,NUM_ARTTOGET))) {
// a lot of article is to be read in server,
// make alert panel and run modal roop
NXModalSession theSession;
int modalStatus;
[oGetArticleNumField setIntValue:artNumAmount];
[iPercentageView resetValue];
[oGetArticleNumWindow makeKeyAndOrderFront:self];
[NXApp beginModalSession:&theSession for:oGetArticleNumWindow];
while ((modalStatus = [NXApp runModalSession:&theSession])
== NX_RUNCONTINUES) {
;
}
if (modalStatus != 1) {
// cancel button was clicked
goto endModal;
}
artWillGetNum = [oGetArticleNumField intValue];
if (artWillGetNum == 0) {
goto endModal;
}
// once stopModal is issued we have to restart modal loop?????
[NXApp endModalSession:&theSession];
[NXApp beginModalSession:&theSession for:oGetArticleNumWindow];
modalStatus = [NXApp runModalSession:&theSession];
first = [groupInfoD firstArticleForAmount:artWillGetNum];
[iPercentageView setMin:(float)first max:(float)last];
DBG(1,fprintf(stderr," first=%d\n",first));
for (i=first; i<=last && modalStatus == NX_RUNCONTINUES; i++) {
// cancel or ok button will break modal loop
modalStatus = [NXApp runModalSession:&theSession];
if ([groupInfoD checkArticleIsRead:i]==NO) {
[self commandHead:i articleDB:articleDB];
}
[iPercentageView displayValue:(float)i];
}
endModal:
[oGetArticleNumWindow orderOut:self];
[NXApp endModalSession:&theSession];
} else {
// article is not so much in server, so will not make any panel
// for alert the user
DPSStartWaitCursorTimer();
DPSFlush();
for (i=first; i<=last; i++) {
if ([groupInfoD checkArticleIsRead:i]==NO) {
[self commandHead:i articleDB:articleDB];
}
}
}
break;
}
// /* add groupInfoD to each articleItem */
// for (i=0; i<[iArticleDB dataCount]; i++) {
// [[iArticleDB objectAt:i] insertKeyedObject:groupInfoD];
// }
[self saveNewsRcFile];
return articleDB;
}
- okArticleNumWindow:sender
{
[NXApp stopModal:1];
return self;
}
- cancelArticleNumWindow:sender
{
[NXApp stopModal:0];
return self;
}
- setOGetArticleNumWindow:kwindow
{
oGetArticleNumWindow = kwindow;
return self;
}
- setOGetArticleNumField:kfield
{
oGetArticleNumField = kfield;
return self;
}
- setIPercentageView:kview
{
iPercentageView = kview;
return self;
}
- (InfoD *)getHeaderByMessageId:(const char *)messageId zone:(NXZone *)zone
{
return([self getHeader:messageId zone:zone]);
}
- (InfoD *)commandHead:(int)knum articleDB:karticleDB
{
char articleNoString[LINE_CHR_MAX];
InfoD *header;
IOrderedListD *articleItem;
sprintf (articleNoString, "%d", knum);
if ((header = [self getHeader:articleNoString zone:headersZone]) != nil) {
[header addInfoInt:knum key:ARTICLE_NUM];
sprintf (articleNoString, "%010d", knum);
articleItem = [[IOrderedListD allocFromZone:headersZone]
initWithKey:articleNoString];
[karticleDB insertKeyedObject:(IKeyedObject *)articleItem];
[articleItem insertKeyedObject:(IKeyedObject *)header];
return(header);
} else {
return(nil);
}
}
- (InfoD *)getHeader:(const char *)articleTag zone:(NXZone *)zone
{
char combuf[512];
int statusCode;
InfoD *header;
char key[256], value[512], *value_p;
char buf[512], *buf_p;
char ch;
sprintf (combuf, "%s %.506s", "head ", articleTag);
statusCode = [self issueCommand:combuf];
switch (statusCode){
case OK_HEAD:
break;
case ERR_NOARTIG:
DBG(1, fprintf(stderr, "WARNING: InntpTalk: \"%s\" no such article"
" in this group\n", articleTag););
fseek (inntpFile, (long)0, SEEK_END);
return(nil);
break;
case ERR_NOART:
DBG(1, fprintf(stderr, "WARNING: InntpTalk: no such article at all"););
fseek (inntpFile, (long)0, SEEK_END);
return(nil);
break;
default:
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("InntpTalk: head command failed, with status code + %d"),
NULL,NULL,NULL, statusCode);
exit(1);
}
header = [[InfoD allocFromZone:zone] initWithKey:HEADER_INFO];
while ((ch = fgetc(inntpFile)) !='.') {
ungetc (ch, inntpFile);
fscanf (inntpFile, "%512[^\r]\r\n", buf);
if ( strchr(buf,':') != NULL ) {
/* first line of each field */
sscanf (buf, "%256[^:]", key);
buf_p = buf;
while (*(buf_p++) != ':')
;
buf_p++; /* skip one space */
strncpy (value, buf_p, sizeof(value));
if ([header addInfoString:value key:key]==NULL) {
NXRunAlertPanel(LoStr("ERROR"),
LoStr("error occured during adding InfoD"),
LoStr("OK"),NULL,NULL);
continue;
}
} else {
/* if field value has multiple lines, go into here */
/* try to add value to previous value */
if ((strlen(value)+strlen(buf)+1) > 511) {
/* over 512, give up to add following value */
continue;
}
if ((value_p=strchr(value, '\0')) == NULL) {
NXRunAlertPanel(LoStr("ERROR"),
LoStr("value has no NULL char"),LoStr("OK"),NULL,NULL);
continue;
}
*(value_p++) = ' '; *value_p = '\0'; /*add space*/
strncpy (value_p, buf, (sizeof(value)-strlen(value)));
if ([header addInfoString:value key:key]==NULL) {
NXRunAlertPanel(LoStr("ERROR"),
LoStr("error occured during adding InfoD"),
LoStr("OK"),NULL,NULL);
continue;
}
}
}
fgetc(inntpFile); fgetc(inntpFile); /* consume '\r' and '\n' */
fseek (inntpFile, (long)0, SEEK_END);
return(header);
}
- (BOOL)sendArticle:(const char *)messageId
{
char combuf[LINE_CHR_MAX];
int statusCode;
char ch[5];
NXStream *stream;
int streamLength;
const char *streamBuffer;
int length, maxLength;
port_t port;
int returnCode;
NXStream *convertedStream;
extern void j2e_conv();
if (messageId == NULL) {
NXRunAlertPanel(LoStr("WARNING"),
LoStr("InntpTalk: can't find message_id"),LoStr("OK"),NULL,NULL);
fseek (inntpFile, (long)0, SEEK_END);
return(NO);
}
sprintf (combuf, "article %.504s", messageId);
statusCode = [self issueCommand:combuf];
if (statusCode != OK_ARTICLE) {
switch (statusCode){
case ERR_NOARTIG:
NXRunAlertPanel(LoStr("WARNING"),
LoStr("InntpTalk: no such article in this group"),
LoStr("OK"),NULL,NULL);
fseek (inntpFile, (long)0, SEEK_END);
return(NO);
break;
case ERR_NOART:
NXRunAlertPanel(LoStr("WARNING"),
LoStr("InntpTalk: no such article at all"),
LoStr("OK"),NULL,NULL);
fseek (inntpFile, (long)0, SEEK_END);
return(NO);
break;
default:
NXRunAlertPanel(LoStr("ERROR"),
LoStr("InntpTalk: body command failed"),LoStr("OK"),NULL,NULL);
DBG(1, {
char buffer[512];
fprintf(stderr, "dump of remaining stream from NNTP "
"server follows:\n");
while(fgets(buffer, sizeof(buffer), inntpFile) != NULL) {
fputs(buffer, stderr);
}
});
fseek (inntpFile, (long)0, SEEK_END);
return(NO);
break;
}
}
stream = NXOpenMemory(NULL, 0, NX_READWRITE);
ch[0] = '\r';
ch[1] = '\n';
ch[2] = fgetc(inntpFile);
ch[3] = fgetc(inntpFile);
ch[4] = fgetc(inntpFile);
while (!(ch[0]=='\r' && ch[1]=='\n' && ch[2]=='.' && ch[3]=='\r' && ch[4]=='\n')) {
NXPutc (stream, ch[2]);
ch[0] = ch[1];
ch[1] = ch[2];
ch[2] = ch[3];
ch[3] = ch[4];
ch[4] = fgetc (inntpFile);
}
// check kanji code on server and convert
if (strcmp(NXGetDefaultValue(OWNER,KANJICODE),"JIS")==0) {
NXSeek(stream, (long)0,NX_FROMSTART);
convertedStream = NXOpenMemory(NULL, 0, NX_READWRITE);
j2e_conv(stream, convertedStream);
NXCloseMemory(stream, NX_FREEBUFFER);
stream = convertedStream;
}
NXPutc (stream, '\0');
streamLength = NXTell(stream);
streamLength -= 1; // ### REWRITE ### for making sure
// '\0' is really not needed any more.
NXGetMemoryBuffer(stream, &streamBuffer, &length, &maxLength);
if ((port = NXPortFromName(MMEDITOR, NULL)) == PORT_NULL) {
NXRunAlertPanel([self name],LoStr("%s is an unknown port."),
LoStr("OK"), NULL, NULL, MMEDITOR);
}
[[NXApp appSpeaker] setSendPort:port];
if ((returnCode = [[NXApp appSpeaker] receiveArticle:streamBuffer
length:streamLength]) != 0) {
NXRunAlertPanel([self name],LoStr("cannot contact port %s."),
LoStr("OK"), NULL, NULL, MMEDITOR);
}
DBG(20, write(creat("readStream", 0666), streamBuffer, streamLength));
NXCloseMemory(stream, NX_FREEBUFFER);
fseek (inntpFile, (long)0, SEEK_END);
return(YES);
}
- (BOOL)canPost
{
// if (*(char *)[[iCurrentNewsgroup link] infoForKey:CANPOST] == 'y') {
if (*(char *)[[iCurrentNewsgroup dataForKey:GROUPINFO]
infoForKey:CANPOST] == 'y') {
return YES;
} else {
return NO;
}
}
- (BOOL)postArticle:(const char *)data length:(int)length
{
int statusCode;
id postingAlertPanel;
NXModalSession postingModalSession;
NXStream *stream, *convertedStream = NULL;
const char *buf;
int max, len;
int bytesSent;
extern void e2j_conv_adj();
DBG(1, fprintf(stderr, "length = %d\n*** start of article ***\n%.10000s\n"
"*** end of article ***\n", length, data));
DBG(20, write(creat("postStream", 0666), data, length));
// check for duplicate message id
/*
if ((header = [self getHeaderByMessageId:messageId
zone:NXDefaultMallocZone()]) != nil) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Message-ID already exists on NNTP server"),
NULL,NULL,NULL);
free(header);
return(NO);
}
*/
switch(NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Post to NNTP Server"),LoStr("Confirm"),LoStr("Cancel"),NULL)) {
case NX_ALERTDEFAULT:
break;
case NX_ALERTALTERNATE:
return(NO);
}
statusCode = [self issueCommand:"POST"];
fseek(inntpFile, (long)0, SEEK_END);
switch (statusCode) {
case CONT_POST:
break;
case ERR_NOPOST:
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("POST command failed. %d posting not allowed."),
NULL,NULL,NULL, statusCode);
return(NO);
default:
// This should never occur!
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("POST command failed. %d is status code returned by NNTP server.") ,NULL,NULL,NULL, statusCode);
return(NO);
}
postingAlertPanel = NXGetAlertPanel(LoStr("NewsBase"),
LoStr("Posting article to NNTP Server... Please wait.")
,NULL, NULL, NULL);
[NXApp beginModalSession:&postingModalSession for:postingAlertPanel];
// copy input data
stream = NXOpenMemory(data, length, NX_READONLY);
NXSeek(stream, (long)0,NX_FROMSTART);
convertedStream = NXOpenMemory(NULL, 0, NX_READWRITE);
// check kanji code on server and convert
if (strcmp(NXGetDefaultValue(OWNER,KANJICODE),"JIS")==0) {
e2j_conv_adj(stream, convertedStream);
} else {
e2e_adj(stream, convertedStream);
}
// convert stream to byte stream
NXGetMemoryBuffer(convertedStream, &buf, &len, &max);
NXCloseMemory(stream, NX_FREEBUFFER);
while (len > 0) {
bytesSent = send(nntpSocket, buf, len, 0);
buf += bytesSent;
len -= bytesSent;
}
if (convertedStream != NULL) {
NXCloseMemory(convertedStream, NX_FREEBUFFER);
}
fseek(inntpFile, (long)0, SEEK_END);
statusCode = [self _getResponse];
fseek (inntpFile, (long)0, SEEK_END);
[NXApp endModalSession:&postingModalSession];
[postingAlertPanel orderOut:self];
NXFreeAlertPanel(postingAlertPanel);
switch (statusCode) {
case OK_POSTED:
/*
// check to make sure
if ((header = [self getHeaderByMessageId:messageId
zone:NXDefaultMallocZone()]) != nil) {
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Posting has been confirmed with NNTP server."),
NULL,NULL,NULL);
free(header);
return(YES);
} else {
// B News Server will not return header
// NXRunAlertPanel(LoStr("NewsBase"),LoStr("Posting failed! check size/newssgroup name."),NULL,NULL,NULL);
// return(NO);
return(YES);
}
*/
return(YES);
case ERR_POSTFAIL:
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("POST command failed. %d posting failed."),
NULL,NULL,NULL, statusCode);
return(NO);
default:
// This should never occur!
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("POST command failed. %d is status code returned by NNTP server.") ,NULL,NULL,NULL, statusCode);
return(NO);
}
}
- readNewsRcFile
{
const char *newsrc_file;
/* "" = $HOME/.newsrc */
newsrc_file = NXGetDefaultValue(OWNER,NEWSRCFILE);
if ((iNewsRc=[[INewsRc allocFromZone:
(NXZone *)newsgroupTreeZone] initFile:newsrc_file])==NULL) {
return NULL;
}
[iNewsRc readRcfile];
return self;
}
- (void)saveNewsRcFile
{
[iNewsRc saveToRcfileFrom:iNewsGroupTreeRoot];
}
- free
{
NXDestroyZone(newsgroupTreeZone);
return([super free]);
}
static void reconnectEvent(DPSTimedEntry teNum, double now, void * nntp)
{
#ifdef DEBUG
fprintf(stderr," ++++reconnecting to nntp server\n");
#endif
if ([(id)nntp reconnectServer] == nil) {
// reconnectServer is inplemented in "INNTP"
// only make new connection and not issue "list" command
NXRunAlertPanel(LoStr("NewsBase"),
LoStr("Can not auto recconect to nntp server."),
LoStr("OK"),NULL,NULL);
[NXApp terminate:nntp];
}
return;
}
- reconnectServer:sender
{
// called from menu and make new tree by "list" command
[super reconnectServer];
[self listAndMakeNewsgroupTree];
return self;
}
- setTimedEntryForReconnect
{
double interval;
int priority = 1;
interval = (double)atof(NXGetDefaultValue(OWNER,RECONNECTTIME)) * 60.0;
DPSAddTimedEntry (interval, reconnectEvent, (id)self, priority);
return self;
}
- cancelArticleMessageID:(const char *)messageID from:(const char *)fromValue
{
NXStream *articlestream;
int len,max,size;
char *buff;
const char *cancelHeader = "Newsgroups: control\r\nSubject: cancel\r\ncontrol: cancel ";
// From field should have been checked before this method.
articlestream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
NXPrintf(articlestream,"%s %s\r\nFrom: %s\r\n.\r\n",
cancelHeader, messageID, fromValue);
NXSeek(articlestream, (long)0,NX_FROMEND);
(long)size = NXTell(articlestream);
NXGetMemoryBuffer(articlestream,&buff, &len, &max);
[self postArticle:(const char *)buff length:(int)size];
NXCloseMemory(articlestream,NX_FREEBUFFER);
return(self);
}
@end